<?php
/**
 * Created by PhpStorm.
 * User: trnall
 * Date: 2019/8/23
 * Time: 19:13
 */

namespace wechat;


use think\Image;
use think\Cache;
use think\Exception;
use think\Log;
use wechat\wxpay\JsApiPay;
use wechat\wxpay\WechatCompanypay;

class Wechat
{
    public $_appid;
    public $_appsecret;
    public $_redirect_uri;
    public $_access_token;
    public $_jsapi_ticket;

    public function __construct($appid = '', $appsecret = '', $redirect_uri = '')
    {
        $wechatInfo = \think\Config::get('wx_gzh');
        $this->_appid = $appid ? $appid : $wechatInfo['appid'];
        $this->_appsecret = $appsecret ? $appsecret : $wechatInfo['appsecret'];
        $this->_redirect_uri = $redirect_uri ? $redirect_uri : '';
    }


    /**
     * 生成授权链接
     * @param $state string 自定义参数
     * @param $scope string 授权方式
     * @return string
     */
    public function createAuthUrl($state = '', $scope = 'snsapi_userinfo')
    {
        $url = 'https://open.weixin.qq.com/connect/oauth2/authorize?';
        $url .= 'appid=' . $this->_appid . '&redirect_uri=' . urlencode($this->_redirect_uri);
        $url .= '&response_type=code&state=' . $state . '&scope=' . $scope . '#wechat_redirect';
        return $url;
    }


    //获取换取用户信息的access_token,openid
    public function getOpenid($code)
    {
        $url = 'https://api.weixin.qq.com/sns/oauth2/access_token?';
        $url .= 'appid=' . $this->_appid . '&secret=' . $this->_appsecret . '&code=' . $code . '&grant_type=authorization_code';
        $result = $this->getData($url, 'openid_accesstoken');
        return $result;
    }

    //获取用户信息
    public function getUserInfo($code)
    {
        $data = $this->getOpenid($code);
        if ($data) {
            $url = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . $data['access_token'] . '&openid=' . $data['openid'] . '&lang=zh_CN';
            $userInfo = $this->getData($url, 'user_info');
            return $userInfo;
        } else {
            return false;
        }
    }

    //获取用户信息
    public function getUserInfo2($access_token, $openid)
    {
        $url = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . $access_token . '&openid=' . $openid . '&lang=zh_CN';
        $userInfo = $this->getData($url, 'user_info');
        return $userInfo;
    }

    public function code2Session($code)
    {
        $url = 'https://api.weixin.qq.com/sns/jscode2session?appid=' . $this->_appid . '&secret=' . $this->_appsecret . '&js_code=' . $code . '&grant_type=authorization_code';
        //$result = $this->getData($url, 'code2Session');
        $result = http_request($url);
        if (empty($result)) {
            throw new Exception('获取session_key及openID时异常，微信内部错误');
        }
        return $result;
    }

    //http get 方法 默认返回数组
    private function httpGet($url, $data_type = 'array')
    {
        $cl = curl_init();
        if (stripos($url, 'https://') !== FALSE) {
            curl_setopt($cl, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($cl, CURLOPT_SSL_VERIFYHOST, FALSE);
            curl_setopt($cl, CURLOPT_SSLVERSION, 1);
        }
        curl_setopt($cl, CURLOPT_URL, $url);
        curl_setopt($cl, CURLOPT_RETURNTRANSFER, 1);
        $content = curl_exec($cl);
        $status = curl_getinfo($cl);
        curl_close($cl);
        if (isset($status['http_code']) && $status['http_code'] == 200) {
            if ($data_type == 'json') {
                $content = json_decode($content);
            }
            return json_decode($content, true);
        } else {
            return FALSE;
        }
    }

    //http post 方法 默认返回数组
    private function httpPost($url, $fields, $data_type = 'array')
    {
        $cl = curl_init();
        if (stripos($url, 'https://') !== FALSE) {
            curl_setopt($cl, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($cl, CURLOPT_SSL_VERIFYHOST, FALSE);
            curl_setopt($cl, CURLOPT_SSLVERSION, 1);
        }
        curl_setopt($cl, CURLOPT_URL, $url);
        curl_setopt($cl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($cl, CURLOPT_POST, true);
        curl_setopt($cl, CURLOPT_POSTFIELDS, $fields);
        $content = curl_exec($cl);
        $status = curl_getinfo($cl);
        curl_close($cl);
        if (isset($status['http_code']) && $status['http_code'] == 200) {
            if ($data_type == 'json') {
                $content = json_decode($content);
            }
            return json_decode($content, true);
        } else {
            return FALSE;
        }
    }

    //记录日志
    public function writeLog($actionname, $errcode = '')
    {
        Log::write('微信公众号错误日志方法：' . $actionname . ' === CODE：' . $errcode, 'WXERRCODE');
        return true;
    }

    //获取基本接口access_token
    public function getAccessToken()
    {
        return (new \wechat\AccessToken($this->_appid, $this->_appsecret))->getAccessToken();
    }

    // 获取 jsSdk 签名 ticket
    private function getJsapiTicket()
    {
        $tiket = Cache::get('jsapi_ticket');
        p([$tiket],'tiket');
        if ($tiket) {
            return $tiket;
        } else {
            $url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' . $this->getAccessToken() . '&type=jsapi';
            $data = $this->getData($url, 'jsapi_ticket');
            p($data, '生成jsapi_ticket');
            if (!$data) {
                $tiket = false;
            } else {
                $tiket = $data['ticket'];
                Cache::set('jsapi_ticket', $tiket, 7000);
            }
            return $tiket;
        }
    }

    /**
     * 获取数据curl get
     * @param $url string 获取链接
     * @param $input string 获取字段
     * @return bool|mixed
     */
    private function getData($url, $input)
    {
        $data1 = [];
        $retry = 3;
        while ($retry--) {
            $data1 = $this->httpGet($url);
            if (!$data1) {
                continue;
            }
            break;
        }
        if (isset($data1['errcode']) && $data1['errcode']) {
            $this->writeLog($input, $data1['errcode']);
            return false;
        }
        return $data1;
    }

    public function postData($url, $field, $input)
    {
        $data1 = [];
        $retry = 3;
        while ($retry--) {
            $data1 = $this->httpPost($url, $field);
            if (!$data1) {
                continue;
            }
            break;
        }
        if (isset($data1['errcode']) && $data1['errcode']) {
            $this->writeLog($input, $data1['errcode']);
            return false;
        }
        return $data1;
    }

    //生成随机字符串
    public function createNonceStr($length = 16)
    {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    //生成签名
    public function creatSign($url)
    {
        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
        $url = $url ?? "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
        $jsapiTicket = $this->getJsapiTicket();
        if (!$jsapiTicket) {
            return false;
        }
        $timestamp = time();
        $nonceStr = $this->createNonceStr();
        // 这里参数的顺序要按照 key 值 ASCII 码升序排序
        $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
        $signature = sha1($string);
        p($signature,'$signature');
        $signPackage = array(
            'jsapi_ticket' => $jsapiTicket,
            "appId" => $this->_appid,
            "nonceStr" => $nonceStr,
            "timestamp" => $timestamp,
            "url" => $url,
            "signature" => $signature,
            "rawString" => $string
        );
        return $signPackage;
    }

    // 发送模板消息

    /**
     * @param $touser string 用户openid
     * @param $msg array 要发送的消息
     * @param $template_id string 模板消息ID
     * @param string $url 模板消息url
     * @param string $color 字体颜色
     * @return bool|string
     */
    public function sendTplMsg($touser, $msg, $template_id, $url = '', $color = '#FF683F')
    {
        if (!$touser || !$template_id) {
            return false;
        }
        if (!is_array($msg) || !$msg) {
            return false;
        }
        $accessToken = $this->getAccessToken();
        if (!$accessToken) {
            return false;
        }
        $postUrl = 'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=' . $accessToken;
        $data = array(
            'touser' => trim($touser),
            'template_id' => trim($template_id),
            'url' => $url,
        );
        $message = array();
        $message['first'] = array(
            'value' => $msg['first'],
            'color' => $color
        );
        $message['keyword1'] = array(
            'value' => $msg['keyword1'],
            'color' => $color
        );
        $message['keyword2'] = array(
            'value' => $msg['keyword2'],
            'color' => $color
        );
        if (array_key_exists('keyword3', $msg)) {
            $message['keyword3'] = array(
                'value' => $msg['keyword3'],
                'color' => $color
            );
        }
        if (array_key_exists('keyword4', $msg)) {
            $message['keyword4'] = array(
                'value' => $msg['keyword4'],
                'color' => $color
            );
        }
        $message['remark'] = array(
            'value' => $msg['remark'],
            'color' => $color
        );
        $data['data'] = $message;
        $data = json_encode($data);
        $result = $this->httpPost($postUrl, $data);
        if (!$result) {
            return false;
        }
        if ($result['errcode'] != 0 || $result['errmsg'] != 'ok') {
            $this->writeLog('sendTplMsg', $result['errcode']);
            return false;
        }
        return true;
    }

    // 发送小程序模板消息

    /**
     * @param $openid string
     * @param $template_id string
     * @param $page string
     * @param $form_id string
     * @param $data array
     * @param null|string $emphasis_keyword // 放大字体
     * @return bool
     */
    public function sendMicroTplMsg($openid, $template_id, $page, $form_id, $data, $emphasis_keyword = null)
    {
        $postData = [];
        $url = 'https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=' . $this->getAccessToken();
        $postData['touser'] = $openid;
        $postData['template_id'] = $template_id;
        $postData['page'] = $page;
        $postData['form_id'] = $form_id;
        $postData['data'] = $data;
        if (!empty($emphasis_keyword)) $postData['emphasis_keyword'] = $emphasis_keyword;
        $postData = json_encode($postData, JSON_UNESCAPED_UNICODE);
        $result = $this->httpPost($url, $postData);
        if (!$result) {
            return false;
        }
        if ($result['errcode'] != 0 || $result['errmsg'] != 'ok') {
            $this->writeLog('sendMicroTplMsg', $result['errcode']);
            return false;
        }
        return true;
    }

    /**
     * 获取用户基本信息 关注之后可以获取到 可以判断用户是否关注
     * @param $openid string 用户OPENID
     * @return array
     */
    public function getBaseInfo($openid = '')
    {
        $url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" . $this->getAccessToken() . "&openid=" . trim($openid) . "&lang=zh_CN";
        $data = $this->getData($url, 'user_base_info');
        return $data;
    }

    /**
     * 发送图文广告消息
     * @param $touser string openid
     * @param $msg array 消息内容
     * @param string $url 跳转链接
     * @param string $imageurl 图片链接
     * @return bool
     */
    public function sendNews($touser, $msg, $url = '', $imageurl = '')
    {
        $time = date('m月d日');
        $time2 = date('Y年m月d日 H:i:s', $_SERVER['REQUEST_TIME']);
        $billcode = $msg['BillCode'];
        $cash = $msg['Cash'];
        $data = [
            'touser' => $touser,
            'msgtype' => 'news',
            'news' => [
                'articles' => [
                    [
                        'title' => '支付成功提醒',
                        'description' => "$time\r\n订单编号:$billcode\r\n支付金额:$cash 元\r\n支付时间:$time2\r\n支付成功了，开始玩耍吧！",
                        'url' => $url,
                        'picurl' => $imageurl,
                    ]
                ]
            ]
        ];
        $postUrl = 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=' . $this->getAccessToken();
        $result = $this->postData($postUrl, json_encode($data, JSON_UNESCAPED_UNICODE), '图文消息');
        if ($result['errcode'] != 0 || $result['errmsg'] != 'ok') {
            $this->writeLog('sendNewsMsg', $result['errcode']);
            return false;
        }
        return true;
    }

    /**
     * 生成小程序码
     * @param $scene
     * @param $page
     * @param int $width
     * @param bool $authColor
     * @param string $dir
     * @return array
     */
    public function setQrcode($scene, $page, $width = 430, $authColor = true, $dir = 'xcxcode/')
    {
        $accessToken = (new AccessToken($this->_appid, $this->_appsecret))->getAccessToken();
        $httpUrl = 'https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=' . $accessToken;
        $postArr = [];
        $postArr['scene'] = $scene;
        $postArr['page'] = $page;
        $postArr['width'] = $width;
        $postArr['auto_color'] = $authColor;
        $res = http_request($httpUrl, 'POST', json_encode($postArr), [], false);
        $resArr = json_decode($res, true);
        $data = ['code' => 200, 'msg' => '', 'data' => null];
        if (is_array($resArr) && count($resArr) > 0) {
            $data['code'] = 403;
            $data['msg'] = '二维码生成失败：' . $resArr['errmsg'];
            return $data;
        }
        $dirPath = $dir . date("Ymd") . '/';
        if (!($_exists = file_exists($dirPath))) {
            mkdir($dirPath, 0755, true);
        }
        $dirPath = $dirPath . md5($page . $scene . time());
        $imgPath = $dirPath . '.png';
        if (file_put_contents($imgPath, $res) == false) {
            $data['code'] = 405;
            $data['msg'] = '二维码生成失败';
        } else {
            /*$image = Image::open('./' . $imgPath);
            // 按照原图的比例生成一个最大为167*167的缩略图并保存为thumb.png
            $thumbImgPath = $dirPath . '_thumb.png';
            $image->thumb(167, 167)->save('./' . $thumbImgPath);
//            if (file_exists('./' . $imgPath))
//                unlink('./' . $imgPath);
            $data['data'] = 'https://' . $_SERVER['SERVER_NAME'] . '/' . $thumbImgPath;*/
            $data['code'] = 200;
            $data['data'] = '/' . $imgPath;
        }
        return $data;
    }

    //企业付款到零钱
    public function payToUser($userId, $orderSn, $money, $desc = '')
    {
        $user = \app\common\model\User::get($userId);
        $wechatCompanypay = new WechatCompanypay();
        $res = $wechatCompanypay->enterprisePay($orderSn, $user['openid'], intval(bcmul($money, 100, 2)), $desc);
//        dump([$orderSn, $user['openid'], intval(bcsub($money, 100, 2)), $desc], $res);
//        return;
        if ($res['return_code'] == 'SUCCESS' && $res['result_code'] == "SUCCESS") {
            return array_merge($res, ['code' => 200]);
        } else {
            return array_merge($res, ['code' => 403]);
        }
    }

    //订单退款
    public function refund(array $data = [])
    {
        $data = [
            'out_trade_no' => $data['out_trade_no'],//商家订单号
            'out_refund_no' => $data['out_refund_no'] ?? mt_rand(10000, 99999) . time(),//商户退款单号
            'total_fee' => $data['total_fee'],//订单总金额，单位：元
            'refund_fee' => $data['refund_fee'],//退款金额，单位：元
        ];
        p($data, 'wechat/refund/requestData');
        $res = (new JsApiPay())->OrderRefundResult($data);
//        Log::write("订单[{$data['out_trade_no']}退款：\r\n 订单总金额：{$data['total_fee']}]\r\n退款金额：{$data['refund_fee']}\r\n返回值：\r\n" . json_encode($res), 'log', true);
        p($res, 'wechat/refund');
        if (isset($res['return_code']) && $res['return_code'] == 'SUCCESS' && isset($res['result_code']) && $res['result_code'] == 'SUCCESS') {
            return ['code' => 200, 'msg' => $res['return_msg']];
        } else {
            return ['code' => 400, 'msg' => $res['return_msg']];
        }
    }

    //发送小程序订阅消息
    public function sendSubscribeMessage(string $openId = '', string $tplId = '', $data, string $page = '/pages/index/index')
    {
        $accessToken = $this->getAccessToken();
        return static::sendSubscribeMessageHandle($accessToken, $openId, $tplId, $data, $page);
    }

    //发送小程序订阅消息
    public static function sendSubscribeMessageHandle(string $accessToken = '', string $openId = '', string $tplId = '', $data, string $page = '/pages/index/index')
    {
        $httpUrl = 'https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=' . $accessToken;
        $postArr = [];
        $postArr['touser'] = $openId;
        $postArr['template_id'] = $tplId;
        $postArr['page'] = $page;
        $postArr['data'] = $data;
        $res = http_request($httpUrl, 'POST', json_encode($postArr), [], false);
        $resArr = json_decode($res, true);
        p(['accessToken' => $accessToken, 'postArr' => $postArr, 'resArr' => $resArr], 'sendSubscribeMessageHandle');
        if (isset($resArr['errcode']) && $resArr['errcode'] == 0 && $resArr['errmsg'] == 'ok')
            return true;
        else
            return false;
    }


}